package br.com.velp.sudecap.daoimpl;

import br.com.velp.sudecap.dao.UsuarioDAO;
import br.com.velp.sudecap.dto.UsuarioParametrosConsultaDTO;
import br.com.velp.sudecap.entidade.DireitoSistema;
import br.com.velp.sudecap.entidade.Usuario;
import br.com.velp.sudecap.util.CriptografiaUtil;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;
import org.hibernate.type.LongType;
import org.hibernate.type.StringType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;

/**
 * <sumario>
 * <objetivo> "Rastreabilidade" </objetivo>
 * <autor> EDUARDO SANTOS DE OLIVEIRA </autor>
 * <versao>1.0.0.0</versao>
 * <data_criacao> 17.10.2012 </data_criacao>
 * <data_ultima_alteracao> N/A </data_ultima_alteracao>
 * <requisitos_afetados> RF001.02 - Listar Usuários / RF001.03 - Cadastrar Usuários </requisitos_afetados>
 * <descricao> Implementação da Interface Responsável Pelas Operações de CRUD Referentes ao Contexto de Usuários </descricao>
 * </sumario>
 */
@Repository("usuarioDAO")
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class UsuarioDAOImpl implements UsuarioDAO {
    
    public static final Long serialVersionUID = 1L;
    
    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public int contarUsuarios(UsuarioParametrosConsultaDTO parametros) {
	Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Usuario.class);
	criteria.setProjection(Projections.rowCount());
	adicionarParametrosConsulta(criteria, parametros);
	return ((Long) criteria.uniqueResult()).intValue();
    }

    @Override
    public List<Usuario> buscarUsuariosPaginados(int firstResult, int maxResults,
	    UsuarioParametrosConsultaDTO parametros, Order order) {

	Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Usuario.class);
	adicionarParametrosConsulta(criteria, parametros);
	criteria.setFirstResult(firstResult);
	criteria.setMaxResults(maxResults);

	if (order != null) {
	    criteria.addOrder(order);
	} else {
	    criteria.addOrder(Order.asc("nome"));
	}

	return criteria.list();

    }

    @Override
    public Long salvar(Usuario value) {
	Long id = (Long) sessionFactory.getCurrentSession().save(value);
	sessionFactory.getCurrentSession().flush();
	return id;
    }

    @Override
    public void atualizar(Usuario value) {
	sessionFactory.getCurrentSession().update(value);
	sessionFactory.getCurrentSession().flush();
    }

    @Override
    public Usuario obterPorId(Long id) {
	return (Usuario) sessionFactory.getCurrentSession().get(Usuario.class, id);
    }

    @Override
    public void excluir(Usuario value) {
	sessionFactory.getCurrentSession().delete(value);
	sessionFactory.getCurrentSession().flush();
    }

    private void adicionarParametrosConsulta(Criteria criteria, UsuarioParametrosConsultaDTO parametros) {
	if (parametros.getStatus() != null) {
	    criteria.add(Restrictions.eq("ativo", parametros.getStatus()));
	}
	if (parametros.getMatricula() != null) {
	    criteria.add(Restrictions.eq("matricula", parametros.getMatricula()));
	}
	if (parametros.getNome() != null && !parametros.getNome().isEmpty()) {
	    criteria.add(Restrictions.ilike("nome", parametros.getNome(), MatchMode.ANYWHERE));
	}
    }

    @Override
    public Usuario recuperarUsuarioPorLoginSenha(String login, String senha) {
	Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Usuario.class);
	criteria.add(Restrictions.eq("login", login));
	criteria.add(Restrictions.eq("senha", CriptografiaUtil.criptografar(CriptografiaUtil.ALGORITMO.MD5, senha)));
	criteria.add(Restrictions.eq("ativo", Boolean.TRUE));
	return (Usuario) criteria.uniqueResult();
    }

    @Override
    public List<DireitoSistema> recuperarPrivilegiosUsuario(Usuario usuario) {

	StringBuilder consulta = new StringBuilder();

	consulta.append(" select dir.COD_DIREITO as id, ");
	consulta.append(" dir.DESC_DIREITO as descricao, ");
	consulta.append(" dir.MODULO as modulo, ");
	consulta.append(" dir.INTERFACE as funcionalidade ");
	consulta.append(" from DIREITO_SISTEMA dir ");
	consulta.append(" left join DIREITO_USU diu on (diu.COD_DIREITO = dir.COD_DIREITO) ");
	consulta.append(" where diu.ID_USU = :idUsuario ");
	consulta.append(" union ");
	consulta.append(" select dir.COD_DIREITO as id, ");
	consulta.append(" dir.DESC_DIREITO as descricao, ");
	consulta.append(" dir.MODULO as modulo, ");
	consulta.append(" dir.INTERFACE as funcionalidade ");
	consulta.append(" from DIREITO_SISTEMA dir ");
	consulta.append(" left join DIREITO_GRUPO_USU dgu on dgu.COD_DIREITO = dir.COD_DIREITO ");
	consulta.append(" where dgu.COD_GRUPO_USU in ");
	consulta.append(" (select diu.COD_GRUPO_USU from DIREITO_USU diu where diu.ID_USU = :idUsuario) ");

	SQLQuery query = sessionFactory.getCurrentSession().createSQLQuery(consulta.toString());

	query.setParameter("idUsuario", usuario.getId());
	query.addScalar("id", LongType.INSTANCE);
	query.addScalar("descricao", StringType.INSTANCE);
	query.addScalar("modulo", StringType.INSTANCE);
	query.addScalar("funcionalidade", StringType.INSTANCE);
	query.setResultTransformer(Transformers.aliasToBean(DireitoSistema.class));

	return query.list();

    }
    
    @Override
    public boolean usuarioJaCadastradoLogin(Usuario usuario){
	Criteria criteria = this.sessionFactory.getCurrentSession().createCriteria(Usuario.class);
	criteria.setProjection(Projections.rowCount());
	criteria.add(Restrictions.eq("login", usuario.getLogin()));
	if(usuario.getId() != null){
	    criteria.add(Restrictions.ne("id", usuario.getId()));
	}
	return ((Long) criteria.uniqueResult()) > 0;
    }
    
    @Override
    public boolean usuarioJaCadastradoMatricula(Usuario usuario){
	Criteria criteria = this.sessionFactory.getCurrentSession().createCriteria(Usuario.class);
	criteria.setProjection(Projections.rowCount());
	criteria.add(Restrictions.eq("matricula", usuario.getMatricula()));
	if(usuario.getId() != null){
	    criteria.add(Restrictions.ne("id", usuario.getId()));
	}
	return ((Long) criteria.uniqueResult()) > 0;
    }
    
    public Session getSession(){
	return this.sessionFactory.getCurrentSession();
    }
    
}
